﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using RayD.Core;
using RayD.App.SystemModule;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace RayD.App.Setup
{
    /// <summary>
    /// 请求响应 中间件
    /// </summary>
    public class RequRespLogMid
    {
        private readonly RequestDelegate _next;
        public RequRespLogMid(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            string requestUrl = string.Empty;       //请求地址
            string requestParams = string.Empty;    //请求参数
            string responseData = string.Empty;     //响应结果
            context.Request.EnableBuffering();      //读取Body配置
            Stream originalBody = context.Response.Body;
            try
            {
                using (var ms = new MemoryStream())
                {
                    /***************************************************************/
                    (requestUrl, requestParams) = RequestData(context.Request);// 存储请求数据
                    context.Response.Body = ms;
                    await _next(context);
                    ms.Position = 0;
                    await ms.CopyToAsync(originalBody);
                    /***************************************************************/

                    #region 记录系统日志
                    UserInfo userinfo;
                    LogApp _logService;
                    var attr = EndpointHelper.GetMetadata<LoggingAttribute>(context);// Action是否贴有日志记录特性
                    if (context.Response.StatusCode == (int)ResponseCode.exception)
                    {
                        // 存储响应数据（存储限制5k）
                        responseData = ResponseData(context.Response, ms);
                        if (responseData.Length > 5_000) responseData = responseData.Substring(0, 5_000) + "......";
                        #region 记录日志(txt)
                        Logger.Log(LogCategory.Exception, new string[] { requestUrl, requestParams, responseData });
                        #endregion

                        #region 记录日志(数据库)
                        userinfo = AuthenticationHelper.LoginUserInfo;
                        _logService = ServiceContainer.Current.GetInstance<LogApp>();
                        _logService.WriteLog(LogCategory.Exception
                            , LogExecuteResult.Fail
                            , responseData
                            , context.Request.Method
                            , requestUrl
                            , requestParams
                            , ""
                            , ""
                            , $"{userinfo.account}({userinfo.realName})"
                            , userinfo.userId
                            , attr?.operateModule);
                        #endregion
                    }
                    else if (!attr.IsEmpty())
                    {
                        // 存储响应数据（存储限制5k）
                        responseData = ResponseData(context.Response, ms);
                        if (responseData.Length > 5_000) responseData = responseData.Substring(0, 5_000) + "......";
                        switch (context.Response.StatusCode)
                        {
                            //操作成功
                            case (int)ResponseCode.success:
                                #region 记录日志(txt)
                                Logger.Log(LogCategory.Operate, new string[] { requestUrl, requestParams, responseData });
                                #endregion

                                #region 记录日志(数据库)
                                userinfo = AuthenticationHelper.LoginUserInfo;
                                _logService = ServiceContainer.Current.GetInstance<LogApp>();
                                _logService.WriteLog(LogCategory.Operate
                                    , LogExecuteResult.Success
                                    , responseData
                                    , context.Request.Method
                                    , requestUrl
                                    , requestParams
                                    , ""
                                    , ""
                                    , $"{userinfo.account}({userinfo.realName})"
                                    , userinfo.userId
                                    , attr?.operateModule);
                                #endregion
                                break;
                            //操作失败
                            case (int)ResponseCode.fail:
                                #region 记录日志(txt)
                                Logger.Log(LogCategory.Operate, new string[] { requestUrl, requestParams, responseData });
                                #endregion

                                #region 记录日志(数据库)
                                userinfo = AuthenticationHelper.LoginUserInfo;
                                _logService = ServiceContainer.Current.GetInstance<LogApp>();
                                _logService.WriteLog(LogCategory.Operate
                                    , LogExecuteResult.Fail
                                    , responseData
                                    , context.Request.Method
                                    , requestUrl
                                    , requestParams
                                    , ""
                                    , ""
                                    , $"{userinfo.account}({userinfo.realName})"
                                    , userinfo.userId
                                    , attr?.operateModule);
                                #endregion
                                break;
                        }
                    }
                    #endregion
                }
            }
            catch (Exception ex)
            {
                #region 记录日志(txt)
                Logger.Log(LogCategory.Exception, new string[] { requestUrl, requestParams, ex.Message });
                #endregion
                throw new Exception("接口异常，在记录日志时失败：" + ex.Message);
            }
            finally
            {
                context.Response.Body = originalBody;
                originalBody.Dispose();
            }
        }

        /// <summary>
        /// 请求数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        private (string, string) RequestData(HttpRequest request)
        {
            string requestUrl = request.Path;
            string requestParams = string.Empty;

            if (request.Method.ToLower().Equals("get"))
            {
                requestParams = request.QueryString.Value;
            }
            else
            {
                var sr = new StreamReader(request.Body);
                requestUrl += request.QueryString;
                requestParams = sr.ReadToEndAsync().Result;

                if (!string.IsNullOrEmpty(requestUrl + requestParams))
                {
                    request.Body.Position = 0;
                }
            }

            return (requestUrl, requestParams);
        }
        /// <summary>
        /// 响应数据
        /// </summary>
        /// <param name="response"></param>
        /// <param name="ms"></param>
        /// <returns></returns>
        private string ResponseData(HttpResponse response, MemoryStream ms)
        {
            ms.Position = 0;
            var ResponseBody = new StreamReader(ms).ReadToEnd();

            // 去除 Html
            var reg = "<[^>]+>";
            var isHtml = Regex.IsMatch(ResponseBody, reg);

            if (!string.IsNullOrEmpty(ResponseBody))
            {
            }
            return ResponseBody;
        }
    }
}
